#include<istream>
#include<stdlib.h>
#include<unistd.h>
#include<sys/sendfile.h>
#include<sys/socket.h>
#include<iostream>
#include <netinet/tcp.h>
#include"Ret.h"

void Ret::send(int sockfd){
  if(!overHead){
    sendHead(sockfd);
  }else{
    sendBody(sockfd);
  }
}

void Ret::sendHead(int sockfd){
  if(!body){
    int length = s.length();
    write(sockfd, s.c_str(), length);
    over = true;
  }else{
    bool on = true;
    setsockopt(sockfd, SOL_TCP, TCP_CORK, &on, sizeof(on));
    int length = s.length();
    write(sockfd, s.c_str(), length);
    sendBody(sockfd);
  }
  overHead = true;
}

void Ret::sendBody(int sockfd){
  auto &type = body->type;
  if(type == "soft"){
    sendSoft(sockfd, std::dynamic_pointer_cast<SoftData>(body));
  }else if(type == "hard"){
    sendHard(sockfd, std::dynamic_pointer_cast<HardData>(body));
  }
}

void Ret::sendSoft(int sockfd, std::shared_ptr<SoftData> &&sd){
  int wn;
  auto &ss = sd->data;
  char buf[size];
  while(true){
    ss.read(buf, size);
    wn = write(sockfd, buf, size);
    if(wn == ss.gcount()){  //全部写入
      if(ss.gcount() < size){  //SoftData读完
	cork = false;
	clearCork(sockfd);
	over = true;
	break;
      }
    }else if(wn == -1){  //EAGAIN 缓存区满
      cork = false;
      clearCork(sockfd);
      ss.seekg(-ss.gcount(), ss.cur);
      break;
    }else{  //没有写完
      ss.seekg((wn - ss.gcount()), ss.cur);
    }
  }
}

void Ret::sendHard(int sockfd, std::shared_ptr<HardData> &&hd){
  int rest = hd->size, fd = hd->fd, wn;
  while(true){
    wn = sendfile(sockfd, fd, nullptr, rest);
    if(wn == rest){  //全部写入
      cork = false;
      clearCork(sockfd);
      hd->size = 0;
      over = true;
      break;
    }else if(wn == -1){  //EAGAIN 缓存区满
      cork = false;
      clearCork(sockfd);
      hd->size = rest;
      break;
    }else{  //没有写完
      rest -= wn;
    }
  }
}

void Ret::clearCork(int sockfd){
  if(cork){
    bool on = false;
    setsockopt(sockfd, SOL_TCP, TCP_CORK, &on, sizeof(on));
  }
}
